//
//  ServicePanelHTSensor.swift
//  home
//
//  Created by Yun Zeng on 2019/9/25.
//  Copyright © 2019 Yun Zeng. All rights reserved.
//

import UIKit

class ServicePanelHTSensor: ServicePanelBase {
    var htSensor: ServiceHTSensor
    
    init(sensor: ServiceHTSensor) {
        self.htSensor = sensor
        super.init(service: htSensor.service)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private var tChartView: HTChartView!
    private var hChartView: HTChartView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.customBar.title = htSensor.name
        self.view.backgroundColor = UIColor(hex: "dedede")
        
        let temperature = NSString(format: "%0.1f", self.htSensor.temperature.value!.toValueFloat()!)  as String
        self.tChartView = HTChartView(title: temperature, type: .temperature)
        self.tChartView.addToSuperView(view: self.view, topAnchor: customBar.bottomAnchor)
        
        let humidity = NSString(format: "%0.0f", self.htSensor.humidity.value!.toValueFloat()!) as String
        self.hChartView = HTChartView(title: humidity, type: .humidity)
        self.hChartView.addToSuperView(view: self.view, topAnchor: tChartView.bottomAnchor)
        
        self.htSensor.temperature.getHistory(completionHandler: self.handleTemperatureMsgData)
        self.htSensor.humidity.getHistory(completionHandler: self.handleHumdityMsgData)
    }
    
    override func updateService() {
        let temperature = NSString(format: "%0.1f", self.htSensor.temperature.value!.toValueFloat()!)  as String
        self.tChartView.title = temperature as String
        let humidity = NSString(format: "%0.0f", self.htSensor.humidity.value!.toValueFloat()!) as String
        self.hChartView.title = humidity
        self.htSensor.temperature.getHistory(completionHandler: self.handleTemperatureMsgData)
        self.htSensor.humidity.getHistory(completionHandler: self.handleHumdityMsgData)
    }
    
    // 处理获取的温度历史数据
    func handleTemperatureMsgData(message: CloudMessage?) -> Void {
        guard let msg = message, let data = msg.data else {
            return
        }
        guard let tdata = CharacteristicStatistics(data: data, type: .temperature) else {
            Logger.Error("invalid data!")
            return
        }
        DispatchQueue.main.async {
            self.tChartView.chartView.data = tdata
            self.tChartView.setNeedsFocusUpdate()
            self.tChartView.updateConstraints()
        }
    }
    
    // 处理获取的湿度历史数据
    func handleHumdityMsgData(message: CloudMessage?) -> Void {
        guard let msg = message, let data = msg.data else {
            return
        }
        guard let hdata = CharacteristicStatistics(data: data, type: .humidity) else {
            Logger.Error("invalid data!")
            return
        }
        DispatchQueue.main.async {
            self.hChartView.chartView.data = hdata
        }
    }
}


// MARK: -配件属性记录统计分析
fileprivate class CharacteristicStatistics {
    struct Records: Codable {
        var aid: String
        var sid: Int
        var cid: Int
        var before: String
        var after: String
        struct Record: Codable {
            var time: String
            var value: AnyJSONType
        }
        var logs: [Record]
    }
    
    var entries = [CGPoint]()
    var average: Float = 0
    
    init? (data: Data, type: ChartType) {
        guard let msg = try? JSONDecoder().decode(Records.self, from: data) else {
            return nil
        }
        
        if msg.logs.isEmpty {
            return nil
        }
        
        var logs = msg.logs
        // 其实时间是否有值
        if logs.first!.time != msg.after {
            logs.insert(Records.Record(time: msg.after, value: logs.first!.value), at: 0)
        }
        // 结束时间是否有值
        if logs.last!.time != msg.before {
            logs.append(Records.Record(time: msg.before, value: logs.last!.value))
        }
    
        // 计算平均值
        for i in 1 ..< logs.count {
            let interval = logs[i].time.toDate().timeIntervalSince(logs[i-1].time.toDate())
            average += Float(interval) * (logs[i].value.toValueFloat()! + logs[i-1].value.toValueFloat()!) / 2
        }
        let interval = logs.last!.time.toDate().timeIntervalSince(logs.first!.time.toDate())
        average = average / Float(interval)
        
        var height: Float = 40.0
        if type == .humidity {
            height = 100.0
        }
        
        let tStart = msg.after.toDate()
        for i in 0 ..< logs.count {
            let xp = logs[i].time.toDate().timeIntervalSince(tStart) / interval
            let yp = (logs[i].value.toValueFloat()!) / height
            self.entries.append(CGPoint(x: xp, y: Double(yp)))
        }
    }
}

// MARK: - 统计图
fileprivate class ChartView: UIView {
    
    private var ctype: ChartType
    
    init(type: ChartType) {
        self.ctype = type
        super.init(frame: .zero)
        self.layer.cornerRadius = 8
    }
    
    private let titleHeight: CGFloat = 30
    private let axisHeight: CGFloat = 30
    private let vspace: CGFloat = 18
    
    var data: CharacteristicStatistics? {
        didSet {
            self.setNeedsDisplay()
        }
    }
    
    private var attributes: [NSAttributedString.Key: Any] =
        [
            .font: UIFont(name: "PingFangSC-Regular", size: 14)!,
            .kern: 0.17,
            .foregroundColor: UIColor(hex: "5F5F5F")
        ]
    
    // 绘制标题
    func drawTitle(rect: CGRect) {
        let path = UIBezierPath(rect: CGRect(x: 0, y: self.titleHeight - 0.5, width: rect.width, height: 0.5))
        UIColor(hex: "D4D4D4").setFill()
        path.fill()
        
        let components = Calendar.current.dateComponents(in: TimeZone.current, from: Date())
        var text: NSString = NSString(format: "%d月%d日", components.month!, components.day!)
        text.draw(at: CGPoint(x: 12, y: 6), withAttributes: attributes)
        
        if let average = self.data?.average {
            if ctype == .temperature {
                text = NSString(format: "平均: %0.1f°", average)
            } else {
                text = NSString(format: "平均: %0.0f%%", average)
            }
        } else {
            text = "平均: --"
        }
        let size = text.boundingRect(with: CGSize(),
                                     options: .usesLineFragmentOrigin,
                                     attributes: attributes, context: nil)
        text.draw(at: CGPoint(x: rect.width - 12 - size.width, y: 6), withAttributes: attributes)
    }
    
    private var tStart = Date()
    
    // 绘制坐标
    func drawAxis(rect: CGRect) {
        // 直线上面的横线
        let path = UIBezierPath(rect: CGRect(x: 0, y: rect.height - self.axisHeight + 0.5, width: rect.width, height: 0.5))
        UIColor(hex: "D4D4D4").setFill()
        path.fill()
        
        // 坐标轴左边的起始竖线
        let lleft = UIBezierPath(rect: CGRect(x: vspace, y: rect.height - self.axisHeight - 3, width: 0.5, height: 7))
        UIColor(hex: "D4D4D4").setFill()
        lleft.fill()
        
        // 坐标轴右边的结束竖线
        let lright = UIBezierPath(rect: CGRect(x: rect.width - vspace, y: rect.height - self.axisHeight - 3, width: 0.5, height: 7))
        UIColor(hex: "D4D4D4").setFill()
        lright.fill()
        
        let interval = self.tStart.timeIntervalSince((tStart.toString(format: "YYYY-MM-dd HH") + ":00:00").toDate())
        let components = Calendar.current.dateComponents(in: TimeZone.current, from: tStart)
        let hour = components.hour!
        
        let radio = CGFloat((3600 - interval) / (24 * 3600))
        let start = vspace + (rect.width - vspace * 2) * radio
        let space: CGFloat = (rect.width - vspace * 2) / 12
        for i in 0 ... 12 {
            let x = (start + CGFloat(i) * space)
            if x > (rect.width - vspace) {
                break
            }
            let y = rect.height - self.axisHeight + 0.5
            // 圆点
            let ovalPath = UIBezierPath(ovalIn: CGRect(x: x  - 1, y: y - 1, width: 2.5, height: 2.5))
            UIColor(hex: "D4D4D4").setFill()
            ovalPath.fill()
            
            // 文字
            let h = (hour + i * 2 + 1) % 24
            if h == 0 {
                attributes[.foregroundColor] = UIColor(hex: "18A2FF")
            } else {
                attributes[.foregroundColor] = UIColor(hex: "5F5F5F")
            }
            
            let text = NSString(format: "%d", h)
            let size = text.boundingRect(with: CGSize(), options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
            text.draw(at: CGPoint(x: x - size.width / 2, y: y + 4), withAttributes: attributes)
        }
        
        // 横线
        attributes[.kern] = -0.53
        if self.ctype == .temperature {
            // 16度以下为寒冷区域
            // 16度-26度为舒适区
            // 26度以上为炎热区
            // 温度区间0-40度
            let height = rect.height - self.axisHeight - self.titleHeight
            var y = rect.height - self.axisHeight - height * 16 / 40
            var path = UIBezierPath(rect: CGRect(x: vspace, y: y, width: rect.width - 2 * vspace, height: 0.5))
            UIColor(hex: "D4D4D4").setFill()
            path.fill()
            
            var text = NSString(format: "16")
            var size = text.boundingRect(with: CGSize(), options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
            text.draw(at: CGPoint(x: vspace - size.width - 1, y: y - size.height / 2), withAttributes: attributes)
            
            
            y = rect.height - self.axisHeight - height * 26 / 40
            path = UIBezierPath(rect: CGRect(x: vspace, y: y, width: rect.width - 2 * vspace, height: 0.5))
            UIColor(hex: "D4D4D4").setFill()
            path.fill()
            
            text = NSString(format: "26")
            size = text.boundingRect(with: CGSize(), options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
            text.draw(at: CGPoint(x: vspace - size.width - 1, y: y - size.height / 2), withAttributes: attributes)
            
        } else {
            // 30%为干燥区域
            // 30%-70%为舒适区
            // 70%以上为潮湿区域
            // 湿度区间0-100%
            let height = rect.height - self.axisHeight - self.titleHeight
            var y = rect.height - self.axisHeight - height * 30 / 100
            var path = UIBezierPath(rect: CGRect(x: vspace, y: y, width: rect.width - 2 * vspace, height: 0.5))
            UIColor(hex: "D4D4D4").setFill()
            path.fill()
            
            var text = NSString(format: "30")
            var size = text.boundingRect(with: CGSize(), options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
            text.draw(at: CGPoint(x: vspace - size.width - 1, y: y - size.height / 2), withAttributes: attributes)
            
            y = rect.height - self.axisHeight - height * 70 / 100
            path = UIBezierPath(rect: CGRect(x: vspace, y: y, width: rect.width - 2 * vspace, height: 0.5))
            UIColor(hex: "D4D4D4").setFill()
            path.fill()
            
            text = NSString(format: "70")
            size = text.boundingRect(with: CGSize(), options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
            text.draw(at: CGPoint(x: vspace - size.width - 1, y: y - size.height / 2), withAttributes: attributes)
            
        }
        attributes[.kern] = 0.17
    }
    
    override func draw(_ rect: CGRect) {
        // 背景
        let path = UIBezierPath(roundedRect: rect, cornerRadius: 8)
        UIColor(hex: "EFEFEF").setFill()
        path.fill()
        
        // 标题
        self.drawTitle(rect: rect)
        self.drawAxis(rect: rect)
    
        // 绘制曲线
        guard let entries = self.data?.entries else {
            return
        }
        if entries.isEmpty {
            return
        }
        
        let toRect: (CGPoint) -> CGPoint = { point in
            let x = self.vspace + (rect.width - 2 * self.vspace) * point.x
            let y = self.titleHeight + (rect.height - self.titleHeight - self.axisHeight) * (1 - point.y)
            return CGPoint(x: x, y: y)
        }
        
        let pathStroke = UIBezierPath()
        pathStroke.move(to: toRect(entries.first!))
        for v in entries {
            pathStroke.addLine(to: toRect(v))
        }
        UIColor(hex: "0098FF").setStroke()
        pathStroke.lineWidth = 1.5
        pathStroke.lineCapStyle = .round
        pathStroke.lineJoinStyle = .round
        pathStroke.stroke()
        
        pathStroke.addLine(to: CGPoint(x: rect.width - vspace, y: rect.height - self.axisHeight))
        pathStroke.addLine(to: CGPoint(x: vspace, y: rect.height - self.axisHeight))
        pathStroke.close()
        
        let gradient = CGGradient(
              colorsSpace: nil,
              colors: [
                  UIColor(hex: "0098FF").cgColor,
                  UIColor(hex: "ffffff", alpha: 0.000).cgColor] as CFArray,
              locations: [0, 1])!
        pathStroke.usesEvenOddFillRule = true
        let context = UIGraphicsGetCurrentContext()!
        context.saveGState()
        pathStroke.addClip()
        context.drawLinearGradient(gradient,
                                   start: CGPoint(x: 0, y: self.titleHeight),
                                   end: CGPoint(x: 0, y: rect.height - self.axisHeight - 30),
                                   options: .drawsAfterEndLocation)
        context.restoreGState()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


fileprivate enum ChartType {
    case temperature
    case humidity
}

fileprivate class HTChartView: UIView {
    private let themeColor = UIColor(hex: "18A2FF")
    private let textColor = UIColor(hex: "5F5F5F")
    private let lineColor = UIColor(hex: "DEDEDE")
    
    // 标题文字
    private lazy var titleAttributes: [NSAttributedString.Key : Any] =
        [
             NSAttributedString.Key.font: UIFont(name: "PingFangHK-Medium", size: 36)!,
             NSAttributedString.Key.kern: -1,
             NSAttributedString.Key.foregroundColor: self.themeColor
        ]
    
    // 图标
    lazy var chartView: ChartView = {
        let view = ChartView(type: self.chartType)
        view.backgroundColor = UIColor.clear
        return view
    } ()
    
    var title: String {
        didSet {
            self.titleLabel.attributedText = NSAttributedString(string: self.title, attributes: titleAttributes)
        }
    }
    
    var chartType = ChartType.temperature
    
    init(title: String, type: ChartType) {
        self.title = title
        self.chartType = type
        
        super.init(frame: .zero)
        self.backgroundColor = UIColor.clear
        
        self.showTitle()
        
        self.addSubview(chartView)
        chartView.translatesAutoresizingMaskIntoConstraints = false
        chartView.topAnchor.constraint(equalTo: self.topAnchor, constant: 60).isActive = true
        chartView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
        chartView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
        chartView.heightAnchor.constraint(equalToConstant: 260).isActive = true
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func addToSuperView(view: UIView, topAnchor: NSLayoutYAxisAnchor) {
        view.addSubview(self)
        self.translatesAutoresizingMaskIntoConstraints = false
        self.topAnchor.constraint(equalTo: topAnchor).isActive = true
        self.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 12).isActive = true
        self.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -12).isActive = true
        self.heightAnchor.constraint(equalToConstant: 321).isActive = true
    }
    
    private var titleLabel: UILabel!
    // 标题
    private func showTitle() {
        let label = UILabel()
        label.attributedText = NSAttributedString(string: self.title, attributes: titleAttributes)
        label.autoresizingMask = .flexibleWidth
        self.addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
        label.topAnchor.constraint(equalTo: self.topAnchor, constant: 8).isActive = true
        self.titleLabel = label
        
        let tlabel = UILabel()
        self.addSubview(tlabel)
        let attributes: [NSAttributedString.Key : Any] =
            [
                .font: UIFont(name: "PingFangHK-Regular", size: 21)!,
                .kern: -0.49,
                .foregroundColor: textColor
            ]
        var ttext = "温度"
        if self.chartType == .humidity {
            ttext = "湿度"
        }
        tlabel.attributedText = NSAttributedString(string: ttext, attributes: attributes)
        tlabel.translatesAutoresizingMaskIntoConstraints = false
        tlabel.trailingAnchor.constraint(equalTo: label.leadingAnchor, constant: -5).isActive = true
        tlabel.centerYAnchor.constraint(equalTo: label.centerYAnchor, constant: 3).isActive = true
        
        let clabel = UILabel()
        self.addSubview(clabel)
        let cattributes: [NSAttributedString.Key : Any] =
            [
                .font: UIFont(name: "PingFangHK-Medium", size: 21)!,
                .kern: -0.49,
                .foregroundColor: themeColor
            ]
        var ctext = "℃"
        if self.chartType == .humidity {
            ctext = "%"
        }
        clabel.attributedText = NSAttributedString(string: ctext, attributes: cattributes)
        clabel.translatesAutoresizingMaskIntoConstraints = false
        clabel.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 2.5).isActive = true
        clabel.centerYAnchor.constraint(equalTo: label.centerYAnchor, constant: 5).isActive = true
    }
}

